001 /*
002 * Copyright 2005 Stephen J. McConnell.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.metro.runtime;
020
021 import java.beans.Expression;
022 import java.beans.Statement;
023 import java.lang.reflect.InvocationTargetException;
024 import java.net.URI;
025 import java.util.ArrayList;
026 import java.util.Hashtable;
027 import java.util.List;
028 import java.util.WeakHashMap;
029 import java.util.EventObject;
030 import java.util.EventListener;
031 import java.rmi.RemoteException;
032
033 import net.dpml.state.State;
034 import net.dpml.state.Transition;
035 import net.dpml.state.Operation;
036 import net.dpml.state.Interface;
037 import net.dpml.state.Trigger;
038 import net.dpml.state.Trigger.TriggerEvent;
039 import net.dpml.state.Action;
040 import net.dpml.state.StateMachine;
041 import net.dpml.state.UnknownOperationException;
042 import net.dpml.state.UnknownTransitionException;
043 import net.dpml.state.IntegrityRuntimeException;
044 import net.dpml.state.StateListener;
045 import net.dpml.state.StateEvent;
046 import net.dpml.state.ExecAction;
047 import net.dpml.state.ApplyAction;
048
049 import net.dpml.util.Logger;
050 import net.dpml.util.EventQueue;
051 import net.dpml.util.EventHandler;
052
053 /**
054 * Default state-machine implementation.
055 *
056 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
057 * @version 1.0.2
058 */
059 public class DefaultStateMachine implements StateMachine, EventHandler
060 {
061 /**
062 * Constant name used to reference a state change in a property event.
063 */
064 public static final String PROPERTY_NAME = "state";
065
066 /**
067 * Validate the state integrity.
068 * @param state the state to validate
069 */
070 public static void validate( State state )
071 {
072 validateState( state );
073 }
074
075 //-------------------------------------------------------------------------------
076 // state
077 //-------------------------------------------------------------------------------
078
079 private State m_state;
080 private boolean m_active = false;
081 private boolean m_disposed = false;
082
083 private final Object m_lock = new Object();
084
085 private final EventQueue m_queue;
086
087 private final WeakHashMap m_listeners = new WeakHashMap();
088
089 private final Logger m_logger;
090
091 //-------------------------------------------------------------------------------
092 // constructor
093 //-------------------------------------------------------------------------------
094
095 /**
096 * Creation of a new state machine using a state graph.
097 * @param queue the event queue
098 * @param logger the logging channel
099 * @param state the state graph
100 * @exception RemoteException if RMI exception occurs
101 */
102 public DefaultStateMachine( EventQueue queue, Logger logger, State state ) throws RemoteException
103 {
104 m_queue = queue;
105 m_logger = logger;
106 m_state = state;
107 }
108
109 //-------------------------------------------------------------------------------
110 // StateMachine
111 //-------------------------------------------------------------------------------
112
113 /**
114 * Add a state change listener to the state machine.
115 * @param listener the state listener
116 */
117 public void addStateListener( final StateListener listener )
118 {
119 if( null == listener )
120 {
121 throw new NullPointerException( "listener" );
122 }
123 checkDisposed();
124 synchronized( m_lock )
125 {
126 m_listeners.put( listener, null );
127 }
128 }
129
130 /**
131 * Remove a state listener from the state machine.
132 * @param listener the state listener
133 */
134 public void removeStateListener( final StateListener listener )
135 {
136 if( null == listener )
137 {
138 throw new NullPointerException( "listener" );
139 }
140 checkDisposed();
141 synchronized( m_lock )
142 {
143 m_listeners.remove( listener );
144 }
145 }
146
147 /**
148 * Return the assigned state event listeners.
149 * @return the event listeners
150 */
151 public EventListener[] getEventListeners()
152 {
153 return getStateListeners();
154 }
155
156 private StateListener[] getStateListeners()
157 {
158 synchronized( m_lock )
159 {
160 return (StateListener[]) m_listeners.keySet().toArray( new StateListener[0] );
161 }
162 }
163
164 /**
165 * Process the supplied event.
166 * @param event the event to process
167 */
168 public void processEvent( EventObject event )
169 {
170 StateListener[] listeners = getStateListeners();
171 for( int i=0; i < listeners.length; i++ )
172 {
173 StateListener listener = listeners[i];
174 if( event instanceof StateEvent )
175 {
176 try
177 {
178 StateEvent e = (StateEvent) event;
179 listener.stateChanged( e );
180 }
181 catch( Throwable e )
182 {
183 final String error =
184 "StateListener notification error.";
185 getLogger().error( error, e );
186 }
187 }
188 }
189 }
190
191 /**
192 * Return the current state.
193 * @return the current state
194 */
195 public State getState()
196 {
197 checkDisposed();
198 synchronized( m_state )
199 {
200 return m_state;
201 }
202 }
203
204 /**
205 * Locate and return the most immediate initialization action defined relative to
206 * the current state. If an action is located within the current state it will be
207 * return otherwise the search will continue up the state graph until either an
208 * action is located or no further parent state is available in which case a null
209 * value is returned.
210 *
211 * @return the initialization action or null if no action declared
212 */
213 public Action getInitializationAction()
214 {
215 checkDisposed();
216 try
217 {
218 return getAction( m_state, Trigger.INITIALIZATION );
219 }
220 catch( Throwable e )
221 {
222 final String error =
223 "Unexpected error during resolution of initialization actions.";
224 throw new IntegrityRuntimeException( error, e );
225 }
226 }
227
228 /**
229 * Locate and return the most immediate termination action defined relative to
230 * the current state. If an action is located within the current state it will be
231 * return otherwise the search will continue up the state graph until either an
232 * action is located or no further parent state is available in which case a null
233 * value is returned.
234 *
235 * @return the termination action or null if no action declared
236 */
237 public Action getTerminationAction()
238 {
239 checkDisposed();
240 try
241 {
242 return getAction( m_state, Trigger.TERMINATION );
243 }
244 catch( Throwable e )
245 {
246 final String error =
247 "Unexpected error during resolution of termination actions.";
248 throw new IntegrityRuntimeException( error, e );
249 }
250 }
251
252 /**
253 * Invoke initialization of the supplied object using the initialization action
254 * declared under the current state path.
255 *
256 * @param object the object to initialize
257 * @return the state established as a sidee effect of the initialization
258 * @exception InvocationTargetException if an invocation error occurs as a
259 * result of initialization
260 */
261 public State initialize( Object object ) throws InvocationTargetException
262 {
263 checkDisposed();
264 ArrayList visited = new ArrayList();
265 try
266 {
267 State result = initialize( visited, object );
268 m_active = true;
269 return result;
270 }
271 catch( UnknownTransitionException e )
272 {
273 final String error =
274 "Internal state machine error raised due to an unresolved transition.";
275 throw new IntegrityRuntimeException( error, e );
276 }
277 catch( UnknownOperationException e )
278 {
279 final String error =
280 "Internal state machine error raised due to an unresolved operation.";
281 throw new IntegrityRuntimeException( error, e );
282 }
283 catch( InvocationTargetException e )
284 {
285 throw e;
286 }
287 catch( Throwable e )
288 {
289 final String error =
290 "Unexpected error during state-machine initialization.";
291 throw new IntegrityRuntimeException( error, e );
292 }
293 }
294
295 /**
296 * Execute a named operation on the supplied object.
297 * @param name an operation name
298 * @param object the target object
299 * @param args operation arguments
300 * @return the result of operation invocation
301 * @exception UnknownOperationException if the operation is unknown
302 * @exception InvocationTargetException if an invocation error occurs as a
303 * result of operation execution
304 */
305 public Object execute( String name, Object object, Object[] args )
306 throws UnknownOperationException, InvocationTargetException
307 {
308 checkDisposed();
309 Operation operation = getOperation( getState(), name );
310 return execute( operation, object, args );
311 }
312
313 /**
314 * Invoke a management method on the supplied object.
315 * @param object the target object
316 * @param method the method name
317 * @param args method parameter arguments
318 * @return the return value
319 * @exception IllegalStateException if the method is recognized but not available
320 * @exception UnknownOperationException if the operation is unknown
321 * @exception InvocationTargetException if an invocation error occurs as a
322 * result of operation execution
323 */
324 public Object invoke( Object object, String method, Object[] args )
325 throws UnknownOperationException, InvocationTargetException, IllegalStateException
326 {
327 checkDisposed();
328
329 // TODO: validate exposure of declaring interface
330
331 try
332 {
333 Expression expression = new Expression( object, method, args );
334 return expression.getValue();
335 }
336 catch( InvocationTargetException e )
337 {
338 throw e;
339 }
340 catch( Exception e )
341 {
342 throw new InvocationTargetException( e );
343 }
344 }
345
346 /**
347 * Apply a named transition to the target object.
348 * @param name the transition name
349 * @param object the object against which any transition handler action are to be applied
350 * @return the state established by the application of the transition
351 * @exception UnknownTransitionException if the transition is unknown
352 * @exception InvocationTargetException if an invocation error occurs as a
353 * result of transition invocation
354 */
355 public State apply( String name, Object object )
356 throws UnknownTransitionException, InvocationTargetException
357 {
358 checkDisposed();
359 synchronized( m_state )
360 {
361 Transition transition = getTransition( m_state, name );
362 return apply( transition, object );
363 }
364 }
365
366 /**
367 * Return all of the available transitions relative to the current state.
368 * @return the available transitions
369 */
370 public Transition[] getTransitions()
371 {
372 checkDisposed();
373 Hashtable table = new Hashtable();
374 State[] states = m_state.getStatePath();
375 for( int i=( states.length-1 ); i>-1; i-- )
376 {
377 State state = states[i];
378 Transition[] transitions = state.getTransitions();
379 for( int j=0; j<transitions.length; j++ )
380 {
381 Transition transition = transitions[j];
382 String name = transition.getName();
383 if( null == table.get( name ) )
384 {
385 table.put( name, transition );
386 }
387 }
388 }
389 return (Transition[]) table.values().toArray( new Transition[0] );
390 }
391
392 /**
393 * Return all of the available operations relative to the current state.
394 * @return the available operations
395 */
396 public Operation[] getOperations()
397 {
398 checkDisposed();
399 Hashtable table = new Hashtable();
400 State[] states = m_state.getStatePath();
401 for( int i=( states.length-1 ); i>-1; i-- )
402 {
403 State state = states[i];
404 Operation[] operations = state.getOperations();
405 for( int j=0; j<operations.length; j++ )
406 {
407 Operation operation = operations[j];
408 String name = operation.getName();
409 if( null == table.get( name ) )
410 {
411 table.put( name, operation );
412 }
413 }
414 }
415 return (Operation[]) table.values().toArray( new Operation[0] );
416 }
417
418 /**
419 * Return all of the available interfaces relative to the current state.
420 * @return the available interface declarations
421 */
422 public Interface[] getInterfaces()
423 {
424 checkDisposed();
425 Hashtable table = new Hashtable();
426 State[] states = m_state.getStatePath();
427 for( int i=( states.length-1 ); i>-1; i-- )
428 {
429 State state = states[i];
430 Interface[] interfaces = state.getInterfaces();
431 for( int j=0; j<interfaces.length; j++ )
432 {
433 Interface data = interfaces[j];
434 String name = data.getName();
435 if( null == table.get( name ) )
436 {
437 table.put( name, data );
438 }
439 }
440 }
441 return (Interface[]) table.values().toArray( new Interface[0] );
442 }
443
444 /**
445 * Invoke termination of the supplied object using the termination action
446 * declared under the current state path.
447 *
448 * @param object the object to terminate
449 * @return the state established as a side-effect of the termination
450 */
451 public State terminate( Object object )
452 {
453 checkDisposed();
454 ArrayList visited = new ArrayList();
455 try
456 {
457 State result = terminate( visited, object );
458 m_active = false;
459 return result;
460 }
461 catch( Throwable e )
462 {
463 e.printStackTrace();
464 return getState();
465 }
466 }
467
468 /**
469 * Returns the active status of the state machine.
470 * @return TRUE if the state machine has invoked initialization and
471 * termination has not been performed otherwise FALSE
472 */
473 public boolean isActive()
474 {
475 return m_active;
476 }
477
478 /**
479 * Dispose of the state machine.
480 */
481 public void dispose()
482 {
483 synchronized( m_lock )
484 {
485 StateListener[] listeners = getStateListeners();
486 for( int i=0; i<listeners.length; i++ )
487 {
488 StateListener listener = listeners[i];
489 removeStateListener( listener );
490 }
491 }
492 m_disposed = true;
493 m_state = null;
494 }
495
496 //-------------------------------------------------------------------------------
497 // implementation
498 //-------------------------------------------------------------------------------
499
500 private String getTag( final Object object )
501 {
502 return DefaultProvider.createTag( object );
503 }
504
505 private State initialize( List list, Object object ) throws Exception
506 {
507 Action action = getInitializationAction();
508 if( null == action )
509 {
510 return m_state;
511 }
512 else if( list.contains( action ) )
513 {
514 return m_state;
515 }
516 else
517 {
518 list.add( action );
519 if( action instanceof Operation )
520 {
521 Operation operation = (Operation) action;
522 execute( operation, object, new Object[0] );
523 return m_state;
524 }
525 else if( action instanceof Transition )
526 {
527 Transition transition = (Transition) action;
528 State current = getState();
529 State result = apply( transition, object );
530 if( !current.equals( result ) )
531 {
532 return initialize( list, object );
533 }
534 else
535 {
536 return getState();
537 }
538 }
539 else
540 {
541 final String error = "Unrecognized action: " + action;
542 throw new IllegalStateException( error );
543 }
544 }
545 }
546
547 private Object execute( Operation operation, Object object, Object[] args ) throws InvocationTargetException
548 {
549 if( null == object )
550 {
551 return null;
552 }
553
554 String method = getMethodName( operation );
555
556 try
557 {
558 Expression expression = new Expression( object, method, args );
559 return expression.getValue();
560 }
561 catch( InvocationTargetException e )
562 {
563 throw e;
564 }
565 catch( Exception e )
566 {
567 throw new InvocationTargetException( e );
568 }
569 }
570
571 private State terminate( List list, Object object ) throws Exception
572 {
573 Action action = getTerminationAction();
574 if( null == action )
575 {
576 return m_state;
577 }
578 else if( list.contains( action ) )
579 {
580 return m_state;
581 }
582 else
583 {
584 if( action instanceof Operation )
585 {
586 Operation operation = (Operation) action;
587 execute( operation, object, new Object[0] );
588 return m_state;
589 }
590 else if( action instanceof Transition )
591 {
592 Transition transition = (Transition) action;
593 State current = getState();
594 State result = apply( transition, object );
595 if( !current.equals( result ) )
596 {
597 return terminate( list, object );
598 }
599 else
600 {
601 return getState();
602 }
603 }
604 else
605 {
606 final String error = "Unrecognized action: " + action;
607 throw new IllegalStateException( error );
608 }
609 }
610 }
611
612 private State apply( Transition transition, Object object ) throws InvocationTargetException
613 {
614 synchronized( m_state )
615 {
616 State context = transition.getState();
617 String target = transition.getTargetName();
618 State state = getState( context, target );
619 Operation operation = transition.getOperation();
620 if( getLogger().isTraceEnabled() )
621 {
622 String name = transition.getName();
623 String tag = getTag( object );
624 getLogger().trace(
625 "applying transition ["
626 + name
627 + "] to "
628 + tag );
629 }
630 if( null != operation )
631 {
632 execute( operation, object, new Object[0] ); // TODO: add resolved values as args
633 }
634 setState( object, state );
635 return state;
636 }
637 }
638
639 private void execute( URI handler, Object object ) throws InvocationTargetException
640 {
641 if( null == object )
642 {
643 return;
644 }
645 String scheme = handler.getScheme();
646 if( "method".equals( scheme ) )
647 {
648 String methodName = handler.getSchemeSpecificPart();
649 if( getLogger().isTraceEnabled() )
650 {
651 String tag = getTag( object );
652 getLogger().trace(
653 "executing operation ["
654 + methodName
655 + "] on "
656 + tag );
657 }
658 Statement statement = new Statement( object, methodName, new Object[0] );
659 try
660 {
661 statement.execute();
662 }
663 catch( InvocationTargetException e )
664 {
665 throw e;
666 }
667 catch( Exception e )
668 {
669 throw new InvocationTargetException( e );
670 }
671 }
672 else
673 {
674 final String error =
675 "Operation scheme not recognized."
676 + "\nScheme: " + scheme
677 + "\nURI: " + handler;
678 throw new IllegalArgumentException( error );
679 }
680 }
681
682 private void setState( final Object object, final State state )
683 {
684 synchronized( m_state )
685 {
686 if( m_state != state )
687 {
688 final State oldState = m_state;
689 m_state = state;
690
691 if( getLogger().isTraceEnabled() )
692 {
693 String tag = getTag( object );
694 getLogger().trace(
695 "transitioning from ["
696 + oldState
697 + "] to ["
698 + state
699 + "] in "
700 + tag );
701 }
702
703 final StateEvent event = new StateEvent( this, oldState, state );
704 m_queue.enqueueEvent( event );
705 }
706 }
707 }
708
709 private Action getAction( State state, TriggerEvent category )
710 throws UnknownTransitionException, UnknownOperationException
711 {
712 Trigger[] triggers = state.getTriggers();
713 for( int i=0; i<triggers.length; i++ )
714 {
715 Trigger trigger = triggers[i];
716 if( trigger.getEvent().equals( category ) )
717 {
718 Action action = trigger.getAction();
719 if( action instanceof ApplyAction )
720 {
721 ApplyAction apply = (ApplyAction) action;
722 String id = apply.getID();
723 return getTransition( state, id );
724 }
725 else if( action instanceof ExecAction )
726 {
727 ExecAction exec = (ExecAction) action;
728 String id = exec.getID();
729 return getOperation( state, id );
730 }
731 else
732 {
733 return action;
734 }
735 }
736 }
737 State parent = state.getParent();
738 if( null != parent )
739 {
740 return getAction( parent, category );
741 }
742 else
743 {
744 return null;
745 }
746 }
747
748 private Transition getTransition( State state, String name ) throws UnknownTransitionException
749 {
750 Transition[] transitions = state.getTransitions();
751 for( int i=0; i<transitions.length; i++ )
752 {
753 Transition transition = transitions[i];
754 if( name.equals( transition.getName() ) )
755 {
756 return transition;
757 }
758 }
759 State parent = state.getParent();
760 if( null == parent )
761 {
762 final String error =
763 "Unable to resolve a transition named ["
764 + name
765 + "] relative to the state ["
766 + state.getName()
767 + "].";
768 throw new UnknownTransitionException( error );
769 }
770 else
771 {
772 try
773 {
774 return getTransition( parent, name );
775 }
776 catch( UnknownTransitionException e )
777 {
778 final String error =
779 "Unable to resolve a transition named ["
780 + name
781 + "] relative to the current state ["
782 + state
783 + "].";
784 throw new UnknownTransitionException( error );
785 }
786 }
787 }
788
789 private Operation getOperation( State state, String name ) throws UnknownOperationException
790 {
791 Operation[] operations = state.getOperations();
792 for( int i=0; i<operations.length; i++ )
793 {
794 Operation operation = operations[i];
795 if( name.equals( operation.getName() ) )
796 {
797 return operation;
798 }
799 }
800 State parent = state.getParent();
801 if( null == parent )
802 {
803 throw new UnknownOperationException( name );
804 }
805 else
806 {
807 return getOperation( parent, name );
808 }
809 }
810
811 //-------------------------------------------------------------------------------
812 // static internals used to validate the integrity of a state graph
813 //-------------------------------------------------------------------------------
814
815 private static void validateState( State state )
816 {
817 Trigger[] triggers = state.getTriggers();
818 validateTriggers( state, triggers );
819 Transition[] transitions = state.getTransitions();
820 validateTransitions( state, transitions );
821 Operation[] operations = state.getOperations();
822 validateOperations( state, operations );
823 State[] states = state.getStates();
824 validateStates( state, states );
825 }
826
827 private static void validateTransitions( State state, Transition[] transitions )
828 {
829 for( int i=0; i<transitions.length; i++ )
830 {
831 Transition transition = transitions[i];
832 validateTransition( state, transition );
833 }
834 }
835
836 private static void validateOperations( State state, Operation[] operations )
837 {
838 for( int i=0; i<operations.length; i++ )
839 {
840 Operation operation = operations[i];
841 validateOperation( state, operation );
842 }
843 }
844
845 private static void validateTriggers( State state, Trigger[] triggers )
846 {
847 for( int i=0; i<triggers.length; i++ )
848 {
849 Trigger trigger = triggers[i];
850 validateTrigger( state, trigger );
851 }
852 }
853
854 private static void validateStates( State state, State[] states )
855 {
856 for( int i=0; i<states.length; i++ )
857 {
858 State s = states[i];
859 validateState( s );
860 }
861 }
862
863 private static void validateTrigger( State state, Trigger trigger )
864 {
865 TriggerEvent event = trigger.getEvent();
866 Action action = trigger.getAction();
867 if( action instanceof Transition )
868 {
869 Transition transition = (Transition) action;
870 validateTransition( state, transition );
871 }
872 else if( action instanceof Operation )
873 {
874 Operation operation = (Operation) action;
875 validateOperation( state, operation );
876 }
877 else if( action instanceof ApplyAction )
878 {
879 ApplyAction apply = (ApplyAction) action;
880 String id = apply.getID();
881 validateTransition( state, id );
882 }
883 else if( action instanceof ExecAction )
884 {
885 ExecAction exec = (ExecAction) action;
886 String id = exec.getID();
887 validateOperation( state, id );
888 }
889 }
890
891 private static void validateTransition( State state, String id )
892 {
893 //System.out.println( "# v/transition: " + id );
894 }
895
896 private static void validateTransition( State state, Transition transition )
897 {
898 String target = transition.getTargetName();
899 State s = getState( state, target );
900 if( null == state )
901 {
902 final String error =
903 "Transition target ["
904 + target
905 + "] does not exist relative to state ["
906 + state;
907 throw new IllegalStateException( error );
908 }
909 }
910
911 private static void validateOperation( State state, String id )
912 {
913 //System.out.println( "# v/operation: " + operation );
914 }
915
916 private static void validateOperation( State state, Operation operation )
917 {
918 //System.out.println( "# v/operation: " + operation );
919 }
920
921 private static State getState( State state, String target )
922 {
923 if( target.startsWith( "/" ) )
924 {
925 //
926 // its an absolute target
927 //
928
929 String spec = target.substring( 1 );
930 State root = state.getStatePath()[0];
931 return getState( root, spec );
932 }
933 else if( target.startsWith( "../" ) )
934 {
935 //
936 // its relative to the state's parent
937 //
938
939 String spec = target.substring( 3 );
940 State parent = state.getParent();
941 if( null != parent )
942 {
943 return getState( parent, spec );
944 }
945 else
946 {
947 final String error =
948 "Invalid relative reference ["
949 + spec
950 + "] passed to root state.";
951 throw new IllegalArgumentException( error );
952 }
953 }
954 else if( target.indexOf( "/" ) > -1 )
955 {
956 //
957 // its a composition address
958 //
959
960 int index = target.indexOf( "/" );
961 String base = target.substring( 0, index );
962 String remainder = target.substring( index + 1 );
963 State s = getState( state, base );
964 return getState( s, remainder );
965 }
966 else
967 {
968 //
969 // its a name relative to the supplied state
970 //
971
972 State[] states = state.getStates();
973 for( int i=0; i<states.length; i++ )
974 {
975 State s = states[i];
976 if( target.equals( s.getName() ) )
977 {
978 return s;
979 }
980 }
981 final String error =
982 "Requested target state ["
983 + target
984 + "] does not exist within the state ["
985 + state.getName()
986 + "].";
987 throw new IllegalArgumentException( error );
988 }
989 }
990
991 private void checkDisposed() throws IllegalStateException
992 {
993 if( m_disposed )
994 {
995 final String error =
996 "Instance has been disposed.";
997 throw new IllegalStateException( error );
998 }
999 }
1000
1001 private String getMethodName( Operation operation )
1002 {
1003 if( null != operation.getMethodName() )
1004 {
1005 return operation.getMethodName();
1006 }
1007
1008 //
1009 // otherwise resolve it using java beans style getXxxx
1010 //
1011
1012 String name = operation.getName();
1013 int n = name.length();
1014 if( n == 0 )
1015 {
1016 throw new IllegalArgumentException( "Operation name is empty." );
1017 }
1018 else if( n == 1 )
1019 {
1020 return "get" + name.toUpperCase();
1021 }
1022 else
1023 {
1024 return "get"
1025 + name.substring( 0, 1 ).toUpperCase()
1026 + name.substring( 1 );
1027 }
1028 }
1029
1030 private static URI createURI( String path ) throws Exception
1031 {
1032 if( null == path )
1033 {
1034 return null;
1035 }
1036 else
1037 {
1038 return new URI( path );
1039 }
1040 }
1041
1042 private Logger getLogger()
1043 {
1044 return m_logger;
1045 }
1046
1047 }